<?php

/**
 * 行云供应商（KA/POP）模式
 * @author chenshubo、huj
 */
namespace App\Service\VendorClient\ShopXingYun;

use App\Service\BaseService;
use App\Service\Code\Normal;
use Service\AppService\IdService;
use App\Service\TaskServer\TaskWorker;
use App\Model\PssModel\ServiceConfig;
use Hyperf\Utils\Coroutine;
use Hyperf\Utils\WaitGroup;

class ShopXingYunApiClient extends BaseService {
    protected $clientConfig;


    public function __construct($apiBody = []) {
        $this->clientConfig = $apiBody;
    }

    /**
     * 创建订单
     */
    public function createOrder($params = []) {
        $orderInfo = $params['supplierOrder'];
        $orderItem = $params['orderGoods'];
        $order     = $params['order'];
        $binfo     = $params['binfo'];

        //支付流水号
        $pay_sn = $order['paySerial'] ?? $orderInfo['pay_sn'];
        //运费
        $deliver_money = $orderInfo['deliver_money'];
        //优惠
        $discount_money = $orderInfo['discount_money'] < 0 ? -$orderInfo['discount_money'] : $orderInfo['discount_money'];

        //下单支付的时候支付信息
        $apply_extends = @json_decode($orderInfo['apply_extends'], true);
        //支付时间
        $pay_time = date('Y-m-d H:i:s', time());
        //支付流水号
        $pay_sn   = $orderInfo['pay_sn'];
        $order_sn = $orderInfo['supplier_dsn'];

        //组装商品数据列表
        $goodsList       = [];
        $goodsTotalMoney = 0;
        foreach ($orderItem as $item) {
            //售价
            $price            = $item['price'];
            $spec_num         = $item['spec_num'];
            $quantity         = $item['quantity'];
            $supplier_skucode = $item['supplier_skucode'];
            $goods_type       = $item['goods_type'];
            $batch_no         = $item['batch_no'];
            $package_num      = $item['package_num'] ?? 0;

            //购买总数量
            $buyNum          = $spec_num * $quantity;
            $goodsTotalPrice = bcmul((string)$price, (string)$quantity, 2);

            $goodsInfo = [
                'sku_code'                => $supplier_skucode,//商品编码（sku_code）
                'package_num'             => $spec_num,//包装规格【如无匹配包装规格可传0，生成订单的包装规格会按下单数量/包装规格，取最大能除尽的规格】
                // 'package_num'             => $package_num,//包装规格【如无匹配包装规格可传0，生成订单的包装规格会按下单数量/包装规格，取最大能除尽的规格】
                'buy_num'                 => $quantity,//购买数量
                'sku_price'               => (string)$price,//渠道售价(包装规格单价,如package_num = 2,此字段表示的是以包装规格为2件计算的单价，单位：元，保留两位小数)
                'sku_tax_amount'          => 0.00,//综合税费(单位：元，保留两位小数)
                'sku_discount_amount'     => 0.00,//平台优惠金额(单位：元，保留两位小数）
                'channel_discount_amount' => 0.00,//渠道优惠金额(单位：元，保留两位小数）
                'sku_pay_amount'          => (string)$goodsTotalPrice,//终端支付金额(单位：元，保留两位小数)
                'price_type'              => $goods_type == 1 ? 1 : 2,//渠道价格类型（1含税，2不含税）【非保税默认为含税】
                'batch_id'                => $batch_no,//批次号
            ];
            ksort($goodsInfo);
            $goodsList[]     = $goodsInfo;
            $goodsTotalMoney = bcadd((string)$goodsTotalMoney, (string)$goodsTotalPrice, 2);
        }

        //订单总价（商品保税价格 + 运费）
        $totalMoney = bcadd((string)$goodsTotalMoney, (string)$deliver_money, 2);

        //订单优惠金额
        $real_total_money      = $orderInfo['real_total_money'];
        $order_discount_amount = bcsub((string)$totalMoney, (string)$real_total_money, 2);
        //商品类型
        $goods_type = current($orderItem)['goods_type'];

        //获取支付方式配置
        $payCommanyCode = $apply_extends['payCommanyCode'] ?? '';
        $PayCompanyCode = $order['payCommanyCode'] ? $order['payCommanyCode'] : $payCommanyCode;
        $pay_value      = ServiceConfig::instance()->getConfigByEventsValue('shopxyb2b', ServiceConfig::TYPE_PAY, $PayCompanyCode);
        if (empty($pay_value)) {
            return Normal::returnCode(Normal::FAIL, "支付公司编码：【{$PayCompanyCode}】未映射，请联系管理员处理");
        }

        //创建订单数据
        $data              = [
            'opcode'                  => 'add_custom_order',
            'merchant_id'             => $this->clientConfig['merchant_id'],
            'order_type'              => $goods_type == 1 ? 1 : 2,
            'push_type'               => 1,//三单对碰推单方式（1.代推订单和运单，2.代推运单）【保税订单必填】
            'merchant_order_id'       => $order_sn,
            'pay_type'                => $this->clientConfig['pay_type'] ?? 1,//付款方式：（1.余额支付，2.信用支付）
            'buyer_name'              => $orderInfo['buyer_realname'],
            'buyer_card_id'           => $orderInfo['buyer_idcard'],
            'recipient_name'          => $orderInfo['buyer_realname'],
            'recipient_card_id'       => $orderInfo['buyer_idcard'],
            'recipient_mobile'        => $orderInfo['recveive_phone'],
            'order_province'          => $orderInfo['province'],
            'order_city'              => $orderInfo['city'],
            'order_area'              => $orderInfo['district'],
            'order_address'           => $orderInfo['receive_address'],
            'order_time'              => date("Y-m-d H:i:s", time()),
            'custom_pay_order'        => $order_sn,
            'pay_time'                => $pay_time,
            //支付方式：(1 支付宝,2 微信,3 商盟,4 汇付,5 通联,9 联动,10 云闪付,11 平安付,12 苏宁易付宝,13 银联,14 汇聚支付 15 新生支付 16 有赞支付 17易生支付 18合利宝 19盛付通 20宝付 21多多支付)【保税订单则为必填项】
            'third_pay_type'          => $pay_value,
            //支付公司编码 【保税订单则为必填项】
            'pay_custom_no'           => $order['payCommanyCode'] ?? $apply_extends['payCommanyCode'],
            //支付公司名称 【保税订单则为必填项】
            'pay_company_name'        => $order['payCommanyName'] ?? $apply_extends['payCommanyName'],
            //交易流水号 【保税订单则为必填项】
            'pay_third_no'            => $order['paySerial'] ?? $apply_extends['paySerial'],
            'sku_list'                => $goodsList,
            'order_pay_amount'        => $real_total_money,
            'order_discount_amount'   => $order_discount_amount,
            'channel_discount_amount' => 0.00,
            'order_freight_amount'    => $deliver_money,
            //'remark'                    => $orderInfo['order_remark'],
            'order_total_amount'      => $totalMoney,
            'ecommerce_name'          => $order['enterpriseName'] ?? $apply_extends['enterpriseName'] ?? '',
            'ecommerce_code'          => $order['enterpriseNum'] ?? $apply_extends['enterpriseNum'] ?? '',
        ];
        $data['sign']      = $this->getSign($data);
        $data['sign_type'] = $this->clientConfig['sign_type'];
        return $this->execute($data);
    }

    /**
     * 取消订单
     */
    public function cancelOrder($params = []) {
        $data              = [
            'opcode'            => 'add_cancel_order',
            'merchant_id'       => $this->clientConfig['merchant_id'],
            'merchant_order_id' => $params['supplierOrder']['supplier_dsn'],
            'cancel_reason'     => $params['order']['exceptReason'] ?? '不想要了'
        ];
        $data['sign']      = $this->getSign($data);
        $data['sign_type'] = $this->clientConfig['sign_type'];
        $res               = $this->execute($data);
        if ($res['code'] == '100191') {
            return Normal::returnCode(Normal::SUC, $res['msg']);
        }
        return $res;
    }

    /**
     * 获取商品列表
     */
    public function queryGoodsList($params = []) {
        if (empty($params['category_id'])) {
            return Normal::returnCode(Normal::FAIL, "except param category_id");
        }

        $data              = [
            'opcode'      => 'get_goods_list',
            'merchant_id' => $this->clientConfig['merchant_id'],
            'page_size'   => $params['limit'] ?? 20,
            'page_index'  => $params['page'] ?? 1,
            'category_id' => $params['category_id']
        ];
        $data['sign']      = $this->getSign($data);
        $data['sign_type'] = $this->clientConfig['sign_type'];
        $response          = $this->execute($data);
        if ($response['code'] != Normal::SUC) {
            $result = ['total' => count([]), 'data' => [], 'response' => $response];
            return Normal::returnCode(Normal::FAIL, "当前分类数据获取异常", $result);
        }

        if (empty($response['data']['goods_list']['list'])) {
            $result = ['total' => count([]), 'data' => [], 'response' => $response];
            return Normal::returnCode(Normal::SUC, "当前分类商品分页获取完成", $result);
        }

        $goodsList   = $response['data']['goods_list']['list'] ?? [];
        $goods_codes = array_filter(array_column($goodsList, 'goods_code'));

        //根据商品列表分页之后查询每页商品详情数据
        $goods_details = $this->channelQueryGoodsDetail($goods_codes);
        //根据商品列表分页之后查询规格
        $skuCodes = $this->getGoodsPageSkuList($goods_details);

        if ($skuCodes) {
            //根据商品列表分页之后查询商品库存数据
            $goods_spec_stock = $this->channelQueryStock($skuCodes);
            //根据商品列表分页之后查询商品价格数据
            $goods_spec_price = $this->channelQueryPrice($skuCodes);
        } else {
            $goods_spec_stock = $goods_spec_price = [];
        }

        //开始组装数据
        $newData = [];
        foreach ($goodsList as $key => & $goods) {
            $goods_code = $goods['goods_code'];
            //如果没得详情数据直接不要
            if (!isset($goods_details[$goods_code])) {
                $goods['sku_list'] = [
                    'stock_info' => [],
                    'price_info' => []
                ];
                $newData[]         = $goods;
                continue;
            }

            $goods_details_clone = $goods_details[$goods_code];
            $sku_list      = $goods_details_clone['sku_list'];
            unset($goods_details_clone['sku_list']);

            foreach ($sku_list as & $skuInfo) {
                $skuInfo['stock_info']     = $goods_spec_stock[$skuInfo['sku_code']] ?? [];
                $skuInfo['price_info']     = $goods_spec_price[$skuInfo['sku_code']] ?? [];
                $goods_details_clone['sku_list'] = $skuInfo;
                $newData[]                 = $goods_details_clone;
                unset($skuInfo);
            }
            unset($goods);
        }
        $result = ['total' => count($newData), 'data' => $newData,'has_next'=>$response['data']['goods_list']['has_next']];
        return Normal::returnCode(Normal::SUC, '获取成功', $result);
    }

    /**
     * 获取商品列表
     */
    public function queryGoodsDetail($params = []) {
        $sku_code = $params['sku_code'];
        //拿到所有SKU
        $detailResult = $this->queryGoodsDetails($sku_code);
        if ($detailResult['code'] != Normal::SUC) {
            return $detailResult;
        }
        $goods_detail     = $detailResult['data']['goods_detail'];
        $goods_spec_stock = $this->queryGoodsDetails($sku_code, 'get_sku_batch');
        // $goods_spec_price = $this->queryGoodsDetails($sku_code, 'get_sku_price');
        $goods_spec_price = $this->queryGoodsDetails($sku_code, 'get_sku_quotes');
        $newData          = [];
        foreach ($goods_detail['sku_list'] as $sku) {
            $sku['stock_info'] = $goods_spec_stock['data']['sku_batch'] ?? [];
            $sku['price_info'] = $goods_spec_price['data'] ?: [];
            $newData[]         = [
                "goods_name"        => $goods_detail['goods_name'],
                "goods_code"        => $goods_detail['goods_code'],
                "category_id1"      => $goods_detail['category_id1'],
                "category_name1"    => $goods_detail['category_name1'],
                "category_id2"      => $goods_detail['category_id2'],
                "category_name2"    => $goods_detail['category_name2'],
                "category_id3"      => $goods_detail['category_id3'],
                "category_name3"    => $goods_detail['category_name3'],
                "brand_id"          => $goods_detail['brand_id'],
                "brand_name"        => $goods_detail['brand_name'],
                "brand_logo"        => $goods_detail['brand_logo'],
                "trade_name"        => $goods_detail['trade_name'],
                "origin_name"       => $goods_detail['origin_name'],
                "origin_icon"       => $goods_detail['origin_icon'],
                "goods_img"         => $goods_detail['goods_img'],
                "goods_thumb_image" => $goods_detail['goods_thumb_image'],
                "goods_detail"      => $goods_detail['goods_detail'],
                "sku_list"          => $sku
            ];
        }
        $result = ['total' => count($newData), 'data' => $newData];
        return Normal::returnCode(Normal::SUC, '获取成功', $result);
    }

    /**
     * 获取所有skucode
     * @param $response
     * @return array
     */
    public function getGoodsPageSkuList($goods_details) {
        $skuCodes = [];
        foreach ($goods_details as $v) {
            $sku_codes = array_column($v['sku_list']??[], 'sku_code');
            if ($sku_codes) {
                $skuCodes = array_merge($skuCodes, $sku_codes);
            }
        }
        return array_unique($skuCodes);
    }

    /**
     * 查询单商品详情
     * @param $sku_code
     * @return mixed
     */
    public function queryGoodsDetails($sku_code, $method = 'get_goods_detail') {
        $data              = [
            'opcode'      => $method,
            'merchant_id' => $this->clientConfig['merchant_id'],
            'sku_code'    => $sku_code
        ];
        $data['sign']      = $this->getSign($data);
        $data['sign_type'] = $this->clientConfig['sign_type'];
        return $this->execute($data);
    }

    /**
     * 批量获取商品
     * @param $category_ids
     * @return array
     */
    public function channelQueryGoodsDetail($goods_codes) {
        $result = [];
        $count  = count($goods_codes);
        $wg     = new WaitGroup();
        $wg->add($count);
        foreach ($goods_codes as $code) {
            co(function () use ($wg, $code, & $result) {
                $data              = [
                    'opcode'      => 'get_goods_detail',
                    'merchant_id' => $this->clientConfig['merchant_id'],
                    'goods_code'  => $code
                ];
                $data['sign']      = $this->getSign($data);
                $data['sign_type'] = $this->clientConfig['sign_type'];
                $response          = $this->execute($data);
                if ($response['code'] == Normal::SUC) {
                    $result[$code] = $response['data']['goods_detail'];
                }
                $wg->done();
            });
        }
        $wg->wait();
        return $result;
    }

    /**
     * 批量获取商品库存
     * @param $sku_codes
     * @return array
     */
    public function channelQueryStock($sku_codes) {
        $result = [];
        $count  = count($sku_codes);
        $wg     = new WaitGroup();
        $wg->add($count);
        foreach ($sku_codes as $code) {
            co(function () use ($wg, $code, & $result) {
                $data              = [
                    'opcode'      => 'get_sku_batch',
                    'merchant_id' => $this->clientConfig['merchant_id'],
                    'sku_code'    => $code,
                ];
                $data['sign']      = $this->getSign($data);
                $data['sign_type'] = $this->clientConfig['sign_type'];
                $response          = $this->execute($data);
                if ($response['code'] == Normal::SUC && !empty($response['data']['sku_batch'])) {
                    $result[$code] = $response['data']['sku_batch'];
                }
                $wg->done();
            });
        }
        $wg->wait();
        return $result;
    }

    /**
     * 批量获取商品价格
     * @param $sku_codes
     * @return array
     */
    public function channelQueryPrice($sku_codes) {
        $result = [];
        $count  = count($sku_codes);
        $wg     = new WaitGroup();
        $wg->add($count);
        foreach ($sku_codes as $code) {
            co(function () use ($wg, $code, & $result) {
                $data              = [
                    // 'opcode'      => 'get_sku_price',
                    'opcode'      => 'get_sku_quotes',
                    'merchant_id' => $this->clientConfig['merchant_id'],
                    'sku_code'    => $code,
                ];
                $data['sign']      = $this->getSign($data);
                $data['sign_type'] = $this->clientConfig['sign_type'];
                $response          = $this->execute($data);
                if ($response['code'] == Normal::SUC && !empty($response['data'])) {
                    $sku_price_list = $response['data'];
                    $result[$code]  = $sku_price_list;
                }
                $wg->done();
            });
        }
        $wg->wait();
        return $result;
    }

    /**
     * 查询商品分类
     * @return array
     */
    public function queryGoodsCategory() {
        $data              = [
            'opcode'        => 'get_goods_category',
            'merchant_id'   => $this->clientConfig['merchant_id'],
            'parent_cat_id' => 0,
        ];
        $data['sign']      = $this->getSign($data);
        $data['sign_type'] = $this->clientConfig['sign_type'];
        $res = $this->execute($data);
        if( $res['code'] != Normal::SUC ) {
            return $res;
        }
        if( empty($res['data']['category_list']) ) {
            return Normal::returnCode(Normal::FAIL,"当前行云分类获取异常");
        }
        if(!isset($this->clientConfig['category']) || empty($this->clientConfig['category'])){
            return $res;
        }
        $targetCategoryIds = explode('|', $this->clientConfig['category']);
        if(!$targetCategoryIds){
            return $res;
        }
        $originCategory = $res['data']['category_list'];
        foreach ($originCategory as $key => $v) {
            if(!in_array($v['category_id'], $targetCategoryIds)){
                unset($originCategory[$key]);
            }
        }
        if( empty($originCategory) ) {
            return Normal::returnCode(Normal::FAIL,"筛选后的分类数据异常");
        }
        $res['data']['category_list'] = array_values($originCategory);
        return $res;

    }

    /**
     * 获取商品sku库存
     */
    public function queryGoodsSkuBatch($params = []) {
        $data              = [
            'opcode'      => 'get_sku_batch',
            'merchant_id' => $this->clientConfig['merchant_id'],
            'sku_code'    => 'MZHFRCG00000513-W',
        ];
        $data['sign']      = $this->getSign($data);
        $data['sign_type'] = $this->clientConfig['sign_type'];
        return $this->execute($data);
    }


    /**
     * 获取sign参数
     */
    private function getSign($param = []) {
        ksort($param);
        $arr = [];
        foreach ($param as $k => $v) {
            if (is_array($v)) {
                $v = $this->getStr($v);
            }
            $arr[] = "{$k}={$v}";
        }
        $str = implode("&", $arr);
        $str = $str . $this->clientConfig['appSecret'];
        return md5($str);
    }

    public function getStr($v) {
        $sku_list = [];
        foreach ($v as $item) {
            $str = [];
            foreach ($item as $key => $v) {
                $str[] = "$key:$v";
            }
            $str        = implode(",", $str);
            $sku_list[] = "{$str}";
        }

        return "[{" . (implode("},{", $sku_list)) . "}]";
    }

    /**
     * CURL请求
     * @param $params
     * @return mixed
     */
    public function execute($param = []) {
        $url       = $this->clientConfig['baseurl'];
        $parameter = [
            [
                'tag'    => 'shopxyb2b_' . $param['opcode'],
                'uid'    => IdService::instance()->getOtherID(),
                'url'    => $url,
                'data'   => $param,
                'method' => 'post',
                'format' => 'json',
                'header' => [],
                'is_not_log' => 'yes'//不记日志
            ],
        ];
        if (in_array($param['opcode'], ['get_goods_category', 'get_goods_list', 'get_goods_detail', 'get_sku_batch', 'get_sku_price','get_sku_quotes'])) {
            $resTask = TaskWorker::instance()->addTask($parameter, 'handleDiableTask');
        } else {
            $resTask = TaskWorker::instance()->addTask($parameter);
        }
        $resTask  = current($resTask);
        $resHttp  = @json_decode($resTask['response']['result'], true);
        $errorMsg = $resHttp['ret_msg'] ?? '请求失败';
        if (isset($resHttp['ret_code']) && $resHttp['ret_code'] == Normal::SUC) {
            return Normal::returnCode(Normal::SUC, "操作成功", $resHttp);
        }
        return Normal::returnCode($resHttp['ret_code'] ?? 0, $errorMsg);
    }
}
